package cn.com.idmy.auth.login;

import cn.com.idmy.auth.context.Contexts;
import cn.com.idmy.auth.event.EventBus;
import cn.com.idmy.auth.exception.AuthException;
import cn.com.idmy.auth.token.TokenManager;
import cn.com.idmy.base.exception.UnauthorizedException;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static cn.com.idmy.auth.AuthConfig.ACCOUNT_TYPE_KEY;

@Slf4j
@Accessors(fluent = true)
public record LoginManager<ID>(TokenManager<ID> tokenManager) {
    public synchronized void init() {
    }

    @NotNull
    public LoginState<ID> login(@NotNull LoginState<ID> state) {
        if (ObjUtil.isEmpty(state.id())) {
            throw new AuthException("id 不能为空");
        }
        var token = tokenManager.get(state);
        if (StrUtil.isBlank(token)) {
            if (state.config() == null) {
                var cfg = tokenManager.tokenConfigDao().getTokenConfig(state.id(), state.accountType(), state.device());
                state.config(cfg);
            }
            tokenManager.create(state);
        } else {
            state.token(token);
        }
        tokenManager.set(state);
        EventBus.doLogin(state);
        return state;
    }

    @NotNull
    public LoginState<ID> login(@NotNull ID id) {
        var state = new LoginState<>(id);
        login(state);
        return state;
    }

    public @NotNull LoginState<ID> state() {
        var state = stateNullable();
        if (state == null) {
            throw new UnauthorizedException();
        } else {
            return state;
        }
    }

    public @Nullable LoginState<ID> stateNullable() {
        return tokenManager.state();
    }

    @NotNull
    public ID id() {
        return state().id();
    }

    @Nullable
    public ID idNullable() {
        var state = stateNullable();
        return state == null ? null : state.id();
    }

    public boolean isLogin() {
        return idNullable() != null;
    }

    public void check() {
        var state = state();
        Contexts.storage().set(ACCOUNT_TYPE_KEY, state.accountType());
    }
}
